home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
CUGUK
/
COMMS
/
C101.ZIP
/
UUPC11XS.ZIP
/
LIB
/
IMPORT.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-11-27
|
26KB
|
582 lines
/*--------------------------------------------------------------------*/
/* i m p o r t . c */
/* */
/* File name mapping routines for UUPC/extended */
/*--------------------------------------------------------------------*/
/*--------------------------------------------------------------------*/
/* Changes Copyright (c) 1989 by Andrew H. Derbyshire. */
/* */
/* Changes Copyright (c) 1990-1992 by Kendra Electronic */
/* Wonderworks. */
/* */
/* All rights reserved except those explicitly granted by the */
/* UUPC/extended license agreement. */
/*--------------------------------------------------------------------*/
/*
* $Id: IMPORT.C 1.2 1992/11/22 21:06:14 ahd Exp $
*
* $Log: IMPORT.C $
* Revision 1.2 1992/11/22 21:06:14 ahd
* Correct mapping of dos paths with trailing slashes
*
*/
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "lib.h"
#include "import.h"
#include "arbmath.h"
#include "hostable.h"
#include "usertabl.h"
#include "security.h"
#define MAX_DIGITS 20 /* Number of digits for arb math */
/*--------------------------------------------------------------------*/
/* Internal function prototypes */
/*--------------------------------------------------------------------*/
#define min(x,y) (((x) < (y)) ? (x) : (y))
currentfile();
/*--------------------------------------------------------------------*/
/* Local function prototypes */
/*--------------------------------------------------------------------*/
static void ImportName( char *local, const char *canon, size_t charsetsize );
/*-------------------------------------------------------------------*/
/* */
/* i m p o r t p a t h */
/* */
/* Convert a canonical name to a format the host can handle */
/* */
/* These routines convert file name between canonical form, which */
/* is defined as a 'unix' style pathname, and the MS-DOS all */
/* uppercase "xxxxxxxx.xxx" format. */
/* */
/* If the canonical name does not have a path, that is the file is */
/* destined for the local spool directory, we can assume the UNIX */
/* name will normally be in a format like this: */
/* */
/* */
/* X.hostid####### (Execute files) */
/* C.hostid####### (Call files) */
/* D.hostid####### (Data files) */
/* */
/* where "hostid" may be most, but not always all, of the local */
/* host or remote host (the file came from or is going to) and */
/* "######" can be any character valid for the UNIX file system. */
/* Note, however, that the routine has to be generic to allow for */
/* other file names to be placed in the spool directory without */
/* collisions. */
/* */
/* Avoiding collisions in the spool directory is important; when */
/* receiving files with mixed case names longer than 11 */
/* characters, sooner or later a file name collision will occur. */
/* */
/* We can also assume that only UUPC will see these names, which */
/* means we can transform the name using any method we choose, so */
/* long as the UUPC functions opening the file always call */
/* importpath, and that importpath is reducible (that is, two */
/* calls to importpath with the same argument always yield the */
/* same result). Note that if end user really wanted the file in */
/* the spool directory, all he has to do is rename the file-- far */
/* better than losing the data because duplicate file names. */
/* */
/* For these files, we map the name as follows: */
/* */
/* 0 - If the name is a valid MS-DOS name, use it without changing */
/* */
/* 1 - Begin the output name by inserting up to the first eight */
/* characters of the remote host name (followed by a slash) as */
/* a subdirectory name. */
/* */
/* 2 - If the input name begins with an uppercase alphabetic */
/* character followed by a period, also insert the alphabetic */
/* (followed by a slash) to make this a second subdirectory. */
/* Then, move the logical start of the input name past the two */
/* characters. */
/* */
/* 3 - Determine the number of characters the local host and */
/* remote hosts have equal to the next characters of the input */
/* name, up to a maximum of 8, and zero the lower of the two */
/* counts. Then, step past the number of characters of the */
/* larger count. */
/* */
/* For example, if the file name is X.keane22222 and the local */
/* host name is kendra (2 characters match) and the remote */
/* host is keane1 (5 characters match), zero the number of */
/* characters matched by kendra, and make the new start of the */
/* file name five characters further (at the first "2"). */
/* */
/* 4 - Convert the remaining string using a base conversion, with */
/* the input character size being from ascii "#" to ascii "z" */
/* (88 characters) to the allowed set of characters in MS-DOS */
/* file names (charset, below, 52 characters). */
/* */
/* 5 - Prepend to the string to be converted the length of the */
/* remote host added to the length of the local host */
/* multiplied by 8 (both lengths were computed in step 3, */
/* above). The base conversion is also applied to this */
/* "character", we which know will be in the range 1-64. */
/* */
/* 6 - If the string created by steps 4 and 5 exceeds 8 */
/* characters, insert a period after the eighth character to */
/* make it a valid MS-DOS file name. If the string created by */
/* steps 4 and 5 exceeds 11 characters, truncate the string by */
/* using the first eight and last three characters. */
/* */
/* 7 - Append the string created in steps 4 through 6 to the path */
/* name created in steps 1 and 2. */
/* */
/* If the canonical name has a path, it is destined for an end */
/* user, so we should not radically transform it like we do for */
/* files in the spool directory. Thus, if the canonical name has */
/* a path, mung the canonical file name as follows: */
/* */
/* 1 - skip any path from the canonical name */
/* */
/* 2 - copy up to 8 character from the canonical name converting . */
/* to _ and uppercase to lowercase. */
/* */
/* 3 - if the name was longer than 8 character copy a . to the */
/* host name and then copy the up to three characters from */
/* the tail of the canonical name to the host name. */
/* */
/* Note that this set of rules will cause a collision with names */
/* that only differ in case, but leaves the name in a recongizable */
/* format for the user. */
/*-------------------------------------------------------------------*/
void importpath(char *local, char const *canon, char const *remote)
{
char *s, *out;
size_t charsetsize; /* Number of allowed characters in
MS-DOS file names */
out = local;
/*--------------------------------------------------------------------*/
/* Verify our parameters */
/*--------------------------------------------------------------------*/
if ( local == NULL )
panic();
if ( canon == NULL )
panic();
/*--------------------------------------------------------------------*/
/* Define our character set */
/*--------------------------------------------------------------------*/
if ( E_charset == NULL )
E_charset = DOSCHARS;
charsetsize = strlen( E_charset );
/*--------------------------------------------------------------------*/
/* Determine if spool file directory */
/*--------------------------------------------------------------------*/
if ((s = strrchr(canon, '/')) == (char *)NULL)
{ /* File for spooling directory, use
internal character set to avoid
collisons */
static size_t range = UNIX_END_C - UNIX_START_C + 1;
/* Determine unique number characters in
the UNIX file names we are mapping */
size_t remlen = min(HOSTLEN, strlen(remote));
/* Length of the remote name passed
in, shortened below to number of
characters matched in name */
size_t nodelen = min(HOSTLEN, strlen(E_nodename));
/* Length of the local host name,
shortened below to number of
characters matched in name */
size_t subscript = 0; /* Value of UNIX character to be
converted to MS-DOS character set */
char *next = local + remlen;
char tempname[FILENAME_MAX];
unsigned char number[MAX_DIGITS];
/* Arbitary length number, for base
conversions */
/*--------------------------------------------------------------------*/
/* Verify we have a remote name */
/*--------------------------------------------------------------------*/
if ( remote == NULL )
panic();
/*--------------------------------------------------------------------*/
/* Put the host name (up to six characters) at the beginning of */
/* the MS-DOS file name as a sub-directory name. */
/*--------------------------------------------------------------------*/
strncpy(local, remote, remlen);
*next++ = '/'; /* Add in the sub-directory seperator */
s = (char *) canon; /* Get the beginnging of the UNIX name */
/*--------------------------------------------------------------------*/
/* Files in the spooling directory generally start with "D.", */
/* "C.", or "X."; strip off any upper case letter followed by a */
/* period into its own directory. */
/*--------------------------------------------------------------------*/
if ((s[0] >= 'A') && (s[0] <= 'Z') && (s[1] == '.'))
{
*next++ = *s; /* Copy the input character */
*next++ = '/'; /* Add the sub-directory indicator too */
s += 2; /* Step input string past the copied
data */
}
while( remlen > 0 )
{
if (equaln(remote,s,remlen))
break;
remlen--;
}
while( nodelen > 0 )
{
if (equaln(E_nodename,s,nodelen))
break;
nodelen--;
}
if (nodelen > remlen )
{
remlen = 0;
s += nodelen;
}
else {
nodelen = 0;
s += remlen;
}
*next = '\0'; /* Terminate first part of host string */
/*--------------------------------------------------------------------*/
/* Create a binary number which represents our file name */
/*--------------------------------------------------------------------*/
for (subscript = 0; subscript < MAX_DIGITS; subscript++ )
number[subscript] = 0; /* Initialize number to zero */
add(number, nodelen + remlen * HOSTLEN, MAX_DIGITS);
/* Append host name info to the
front of the converted string */
while( (*s != '\0') && (*number == '\0'))
{
mult(number, range, MAX_DIGITS); /* Shift the number over */
add(number, *s++ - UNIX_START_C , MAX_DIGITS);
/* Add in new low order */
} /* while */
/*-------------------------------------------------------------------*/
/* We now have stripped off the leading x. and host name, if any; */
/* now, convert the remaining characters in the name by doing a */
/* range to charset base conversion. */
/*-------------------------------------------------------------------*/
out = &tempname[FILENAME_MAX];
*--out = '\0'; /* Terminate the string we will build */
/*--------------------------------------------------------------------*/
/* Here's the loop to actually do the base conversion */
/*--------------------------------------------------------------------*/
while(adiv( number, charsetsize, &subscript, MAX_DIGITS))
*--out = E_charset[ subscript ];
/*--------------------------------------------------------------------*/
/* The conversion is done; now squeeze it into an 11 character */
/* MS-DOS name with period. */
/*--------------------------------------------------------------------*/
ImportName( next, out, charsetsize);
}
else { /* Not file for spooling directory, convert it */
char *in = (char *) canon;
/*--------------------------------------------------------------------*/
/* Handle leading drive letter (ignore it, assuming valid) */
/*--------------------------------------------------------------------*/
if ( isalpha( *in ) && (in[1] == ':'))
{
*out++ = *in++; /* The drive letter */
*out++ = *in++; /* The colon making it a driver letter */
} /* if */
if ( *in == '/' ) /* Absolute path name? */
*out++ = *in++; /* Yes, step past it */
while( *in == '/') /* Additional slashes? */
in++; /* Skip them, they mean nothing */
s = strchr( in, '/' ); /* Get end of next path segment */
/*--------------------------------------------------------------------*/
/* Now convert each simple name in the path */
/*--------------------------------------------------------------------*/
while ( *in )
{
if ( s != NULL )
*s = '\0'; /* Truncate input string to simple name */
ImportName( out, in , charsetsize );
if ( s == NULL )
break;
out = out + strlen( out );
*out++ = *s++ = '/'; /* Restore path to input and output */
in = s; /* Remember start of this simple name */
while( *in == '/') /* Additional slashes? */
in++; /* Skip them, they mean nothing */
s = strchr( in , '/' );
}
} /* else */
printmsg( 3, "ImportPath: Mapped %s to %s", canon, local );
} /*importpath*/
/*--------------------------------------------------------------------*/
/* I m p o r t N a m e */
/* */
/* Translate a simple DOS name without the path */
/*--------------------------------------------------------------------*/
static void ImportName( char *local, const char *canon, size_t charsetsize )
{
char *in = (char *) canon;
char *out = local;
size_t len = strlen( canon );
size_t column;
char *best_period = NULL; /* Assume no prince charming */
if ( strchr(canon,'/') != NULL )
{
printmsg(0,"ImportName: Parameter error, not simple name: %s",
canon);
panic();
}
if ( len == 0 )
{
printmsg(0,"ImportName: Parameter error, zero length input");
panic();
}
/*--------------------------------------------------------------------*/
/* If a valid DOS name, use it as-is */
/*--------------------------------------------------------------------*/
if (ValidDOSName( canon ))
{
strcpy( local, canon );
return;
}
/*--------------------------------------------------------------------*/
/* If the dataset name has a period, use it. The rule we */
/* follow is use the last period in the second through ninth */
/* characters, otherwise use the last period in the dataset */
/* name with the exception of leading period. */
/* */
/* In any case, we only copy up to eight characters for the */
/* dataset name and up to three characters for the extension. */
/*--------------------------------------------------------------------*/
for ( column = 1; (column < 9) && (in[column] != '\0') ; column++)
{
if ( in[column] == '.')
{
strncpy( out, in, column + 5 );
/* Period, 3 char extension,
and terminating \0 */
best_period = &out[column];/* Remember output location of
period in name */
if ( len > (column + 4) ) /* Need to trunc extension to 3? */
strcpy( out + column + 1, in + len - 3 ); /* Yes */
break;
} /*if */
} /* if */
/*--------------------------------------------------------------------*/
/* No period in the first eight characters, search the rest of */
/* the name for the last period (unless period is very last */
/* character in the string). */
/*--------------------------------------------------------------------*/
if ( best_period == NULL )
{
strncpy( out , in , 8);
best_period = strrchr( in+1 , '.');
if ( (best_period != NULL) && (best_period[1] != '\0') )
{
strncpy( &out[8], best_period, 4 ); /* Plus period and 3
in extension */
if ( strlen( best_period) > 4 ) /* Long Extension? */
out[12] = '\0'; /* Yes --> Truncate */
} /* if */
else { /* No periods at all, generate one
if needed for long name */
if ( len > 8 )
{
out[8] = '.';
strcpy(&out[9], in + max(8,(len - 3)) );
} /* if ( len > 9 ) */
} /* else */
best_period = &out[8]; /* Remember location of
period, okay if past
end of string */
} /* if ( best_period == NULL ) */
/*--------------------------------------------------------------------*/
/* Now, clean up any invalid characters */
/*--------------------------------------------------------------------*/
if ( out[ strlen( out ) - 1 ] == '.' ) /* Trailing period? */
out[ strlen( out ) - 1 ] = '\0'; /* Just truncate string */
while( *out != '\0')
{
int c ;
if ( isupper( *out ))
c = tolower( *out );
else
c = *out;
if ((out != best_period) && (strchr( E_charset, c ) == NULL ))
{
if ( c > 'z' )
c -= 62;
else if ( c > 'Z' )
c -= 36;
else if ( c > '9' )
c -= 10;
*out = E_charset[ (c - UNIX_START_C) % charsetsize ];
}
out++; /* Step to next character */
} /* while( *out != '\0') */
/*--------------------------------------------------------------------*/
/* Report our results and return */
/*--------------------------------------------------------------------*/
printmsg( 5,
"ImportName: Mapped %s to %s", canon, local );
} /* ImportName */
/*--------------------------------------------------------------------*/
/* V a l i d D O S N a m e */
/* */
/* Validate an MS-DOS file name */
/*--------------------------------------------------------------------*/
boolean ValidDOSName( const char *s)
{
char *ptr;
size_t len = strlen ( s );
char tempname[FILENAME_MAX];
/*--------------------------------------------------------------------*/
/* Define our character set */
/*--------------------------------------------------------------------*/
if ( E_charset == NULL )
E_charset = DOSCHARS;
/*--------------------------------------------------------------------*/
/* Name must be 12 characters or less */
/*--------------------------------------------------------------------*/
if (len > 12)
return FALSE;
strcpy( tempname, s); /* Make a temp copy we can alter */
/*--------------------------------------------------------------------*/
/* Simple file name without extension must be eight chracters */
/* or less */
/*--------------------------------------------------------------------*/
ptr = strrchr(tempname, '.');
if (ptr == NULL)
{
if (len > 8)
return FALSE;
}
/*--------------------------------------------------------------------*/
/* Period must be in second through ninth character */
/*--------------------------------------------------------------------*/
else {
if ((ptr == tempname) || (ptr > &tempname[8]))
return FALSE;
/*--------------------------------------------------------------------*/
/* Extension must be three characters or less */
/*--------------------------------------------------------------------*/
if ( strlen( ptr ) > 4) /* Three characters plus the period? */
return FALSE; /* No --> Too much */
/*--------------------------------------------------------------------*/
/* Only one period */
/*--------------------------------------------------------------------*/
if (ptr != strchr(tempname, '.'))
return FALSE;
} /* else */
/*--------------------------------------------------------------------*/
/* Must only be valid MS-DOS characters */
/*--------------------------------------------------------------------*/
strlwr( tempname ); /* Map into our desired character set */
if ( ptr != NULL )
*ptr = 'x'; /* We've already accounted for the
period, don't let it ruin our day */
if (strspn(tempname, E_charset ) == len)
{
printmsg(9,"ValidDOSName: \"%s\" is valid", s);
return TRUE;
}
else
return FALSE;
} /* ValidateDOSName */